#ifndef SIPUSERAGENT_HPP__
#define SIPUSERAGENT_HPP__

#include "SipResipConfigure.hpp"
#include "SipUAParameters.hpp"
//#include "SipDialogSet.hpp"
//#include "SipRealPlayAdaptor.hpp"
//#include "SipKeepAliveAdaptor.hpp"

#include "resip/stack/TransactionUser.hxx"
#include "resip/stack/SipStack.hxx"
#include "resip/stack/SelectInterruptor.hxx"
#include "resip/stack/InterruptableStackThread.hxx"


namespace wtsip{

class CSipDialogSet;
class CSipRealPlayAdaptor;
class CSipKeepAliveAdaptor;
class CSipDevInfoSession;
class CSipDlgSetHandle;
class CSipUserAgent;
class CSipSrvTransaction;
class CSipDialogBase;
class CSipInviteDialog;
class CSipRegistration;
class CSipSubscription;
class CSipClnTransaction;


class RESIP_PUBLIC CSipUserAgentListener{
public:
    virtual bool onRequest(CSipDialogBase& dlg, SipMessage& msg) = 0;

    virtual bool onRequest(CSipSrvTransaction& srv, SipMessage& msg) = 0;    

    virtual bool onResponse(CSipDialogBase& dlg, SipMessage& msg) = 0;

    virtual bool onResponse(CSipClnTransaction& cln, SipMessage& msg) = 0;
};


class RESIP_PUBLIC CSipUserAgent: public TransactionUser, public ThreadIf{

public:
    CSipUserAgent(CSipUAParameters& param);
    
    virtual ~CSipUserAgent();

    //virtual bool startup();

    virtual void thread();

    virtual void shutdown();

    //virtual bool process();

    SipStack& getStack();

    CSipUAParameters& getParam();

    CSipDialogSet& getDialogSet();

    virtual const Data& name() const;

    SipMessage* createRequest(NameAddr& to, NameAddr& from, MethodTypes mth);

    SipMessage* createRequest(const resip::Uri& to, const resip::Uri& from, MethodTypes mth);

    SipMessage* createResponse(SipMessage& msg, int code);

    /////////////////  Create Special Message /////////////////////

    SipMessage* createInviteMsg(const resip::Uri& to, const resip::Uri& from);

    SipMessage* createInviteMsg(NameAddr& to, NameAddr& from);

    SipMessage* createRegisterMsg(const resip::Uri& to, const resip::Uri& from);

    SipMessage* createRegisterMsg(NameAddr& to, NameAddr& from);

    SipMessage* createSubscribeMsg(const resip::Uri& to, const resip::Uri& from);

    SipMessage* createSubscribeMsg(NameAddr& to, NameAddr& from);

    //////////////// Create Dialog /////////////////////

    CSipInviteDialog* createInviteDlg(SipMessage& msg);

    CSipInviteDialog* createInviteDlg(const resip::Uri& remote, const resip::Uri& local);

    CSipRegistration* createRegistration(SipMessage& msg);

    CSipRegistration* createRegistration(const resip::Uri& remote, const resip::Uri& local);

    CSipSubscription* createSubscription(SipMessage& msg);

    CSipSubscription* createSubscription(const resip::Uri& remote, const resip::Uri& local);

    ////////////// Create Transaction ////////////////////

    CSipClnTransaction* createClnTransaction(SipMessage& request);

    CSipSrvTransaction* createSrvTransaction(SipMessage& request);

    bool send(std::auto_ptr<SipMessage> msg);

	bool postTimerMessage(ApplicationMessage* msg, int seconds);

    bool postSelfMessage(TransactionMessage* msg);

    bool dispatch(SipMessage* msg, CSipDialogBase* dlg = 0);

    bool destroyClientTran(const resip::Data& tid);

    bool destroyServerTran(const resip::Data& tid);

    bool registerListener(CSipUserAgentListener* ls);

    bool unregisterListener();

protected:

    virtual bool init();

    //virtual bool onProcess(SipMessage* msg);

    //virtual bool enableProcess();

private:
    
    bool m_shuttingDown;

    CSipUAParameters m_param;
    
    CSipDialogSet* m_DialogSet;

    CSipUserAgentListener* m_uaListener;

    //std::list<CSipDlgAdaptorBase*> m_Adaptors;

    //std::list<CSipDlgAdaptorBase*> m_shutdownAdaptors;

    std::map<resip::Data, CSipSrvTransaction*> m_srvTransations;

    std::map<resip::Data, CSipClnTransaction*> m_clnTransations;

    SipStack* m_Stack;

    SipStackOptions* m_StackOptions;

    SelectInterruptor* m_SelectInterruptor;

    InterruptableStackThread* m_StackThread;
};

}



#endif
